/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
#ifndef _JOYSTICKCONTROLEVENT_H_
#define _JOYSTICKCONTROLEVENT_H_

#include <vector>
#include <wx/event.h>

#include "JoystickControlUtils.h"

// Custom events use wxJoystickEvent, but differ somewhat in content.
// m_zPosition tells to which axis the movement event is related to.
// X and Y axis are sent in one packet, others by themselves.

// Define custom eventids for own joystickreader-thread.
DECLARE_EVENT_TYPE(wxEVT_GIMUI_JOYSTICK_MOVE, -1)
DECLARE_EVENT_TYPE(wxEVT_GIMUI_JOYSTICK_BUTTON_UP, -1)
DECLARE_EVENT_TYPE(wxEVT_GIMUI_JOYSTICK_BUTTON_DOWN, -1)

/**
 * \struct AxisInfo
 * Helper-struct to enable inverting axis-values at the lowest level.
 */
struct AxisInfo {
  AxisInfo(const int pos);
  
  float position;
  bool inversion;
};

typedef std::vector< AxisInfo > t_axisList;
typedef t_axisList::iterator t_axisListIterator;
typedef t_axisList::const_iterator t_axisListConstIterator;

class JoystickStatus {
  public:
    JoystickStatus(const int nAxes = 0,
                   const int nButtons = 0);
    //JoystickStatus(const JoystickStatus &right);
    ~JoystickStatus();

    inline bool isReadable() const { return readable; }
    inline void setReadModeOn() { readable = true; }
    inline void setReadModeOff() { readable = false; }

    inline int getNumberAxes() { return numberOfAxes; }    
    inline int getNumberButtons() { return numberOfButtons; }
    
    float getPosition(int axisNumber) const;
    bool getInversion(int axisNumber) const;
    
    inline int getButtonState() const { return buttons; }
    bool getSingleButtonState(const int buttonNumber) const;
    
    /*
    bool setPosition(const int axisNumber,
                     const float axisValue);
    */
    bool setInversion(const int axisNumber,
                      const bool invert);
                      
    inline void setButtonState(const int aButtonState)
        { buttons = aButtonState; }
    
    /**
     * Compares given value to specified axis.
     * Used to put in a new axis-value from wx, does axis-inversion.
     * 
     * \param axisNumber
     * \param axisValue 
     * \return -1 if axis was not found. 0 for no change and 1 if value
     * had changed.
     */
    int compareToAxis(const int axisNumber,
                      const float axisValue);
                      
    /**
     * Compares given value to specified button.
     * 
     * \param buttonNumber
     * \param buttonValue 
     * \return -1 if button was not found. 0 for no change and 1 if value
     * had changed.
     */
    int compareToButtons(const int buttonValues);

  private:
    bool readable;
    int numberOfAxes;
    int numberOfButtons;
    
    int buttons;
    t_axisList axes;
};

// Declare own proper joystick-event class.
class GIMUIJoystickEvent : public wxEvent
{
  // Mandatory methods for creating an event.
  public:
    GIMUIJoystickEvent(const GIMUIJoystickEvent &original);
    GIMUIJoystickEvent(int id = 0,
                       wxEventType commandType = wxEVT_NULL);
    GIMUIJoystickEvent(wxEventType commandType,
                       const JoystickStatus &joyStatus);
    
    virtual wxEvent *Clone() const { return new GIMUIJoystickEvent(*this); }
    
    //void CopyObject (wxObject& obj) const;
    
    DECLARE_DYNAMIC_CLASS(GIMUIJoystickEvent)
    
  // Own parameters and methods.
    
    /**
     * \return Id of the changed axis or button depending on eventtype.
     */
    inline int getChangeId() const { return changeId; }
    
    /**
     * \return Id of the joystick.
     */
    inline int getJoystickId() const { return joystickId; }
    
    
    inline void setChangeId(const int aChangeId)
        { changeId = aChangeId; }
    inline void setJoystickId(const int aJoystickId)
        { joystickId = aJoystickId; }
        
    JoystickStatus currentStatus; ///< Current joystick status (axes, buttons)
  
  private:
    int changeId; ///< Tells number of the axis or button to which this event is related to.
    int joystickId; ///< Id of the joystick.
};

#endif // _JOYSTICKCONTROLEVENT_H_
